/*
 * Implementacion de la Tabla de Simbolos para el lenguaje C Minus.
 * 
 * Basado en el proyecto descrito en: 
 * Louden, K. (1997). Compiler Construction: Principles and Practice. Boston: PWS.
 * 
 * @ Project: Compiler
 * @ File Name: SymTable.java
 */
package cml.analyzing;

import java.util.Enumeration;
import java.util.Hashtable;

public class SymTable {
	
	private String name;
	private int scopeLevel;
	private boolean active;
	private Hashtable<String, Symbol> symbols;
	
	/*
	 * Constructor de la clase.
	 * 
	 * @param	name		nombre de la table
	 * @param	scopeLevel	nivel de bloque de la tabla
	 */
	public SymTable(String name, int scopeLevel) {
		
		this.name = name;
		this.scopeLevel = scopeLevel;
		this.active = true;
		this.symbols = new Hashtable<String, Symbol>();
	}
	
	/*
	 * Agrega un simbolo a la tabla.
	 * 
	 * @param	sym	simbolo a agregar
	 */
	public void addSymbol(Symbol sym) {
		
		this.symbols.put(sym.getName(), sym);
	}
	
	/*
	 * Establece si la tabla esta activa o no.
	 * 
	 * @param	active	si <code>true</code> la tabla esta activa; en caso contrario no
	 */
	public void setActive(boolean active) {
		
		this.active = active;
	}
	
	/*
	 * Regresa el nombre de la tabla.
	 * 
	 * @return	el nombre
	 */
	public String getName() {
		
		return this.name;
	}
	
	/*
	 * Regresa el nivel de bloque de la tabla.
	 * 
	 * @return	nivel de bloque
	 */
	public int getScopeLevel() {
		
		return this.scopeLevel;
	}
	
	/*
	 * Regresa la lista de nombres de los simbolos en la tabla.
	 * 
	 * @return	enumeracion de los nombres
	 */
	public Enumeration<String> names() {
		
		return this.symbols.keys();
	}
	
	/*
	 * Regresa un simbolo por nombre.
	 * 
	 * @return	el simbolo
	 */
	public Symbol getSymbol(String name) {
		
		return this.symbols.get(name);
	}
	
	/*
	 * Indica si esta activa o no la tabla.
	 * 
	 * @return	si <code>true</code> la tabla esta activa; en caso contrario no
	 */
	public boolean isActive() {
		
		return this.active;
	}
	
	/*
	 * Indica si la tabla tiene o no simbolos.
	 * 
	 * @return	si <code>true</code> la tabla esta vacia; en caso contrario no
	 */
	public boolean isEmpty() {
		
		return this.symbols.isEmpty();
	}
	
	/*
	 * Imprime la tabla en consola.
	 */
	public static void printTable(SymTable table) {
		
		System.out.println("============================================================================" +
				"=============================================");
		System.out.format("%1$-102s", "Tabla: " + table.getName());
		System.out.println("Nivel de bloque: " + table.getScopeLevel());
		System.out.println("----------------------------------------------------------------------------" +
				"---------------------------------------------");
		System.out.format("%1$-77s", "Simbolo");
		System.out.format("%1$-35s", "Tipo");
		System.out.println("No. Linea");
		
		System.out.format("%1$-77s", "-------");
		System.out.format("%1$-35s", "----");
		System.out.println("---------");
		
		Enumeration<String> names = table.names();
		
		while(names.hasMoreElements()) {
			
			String name = names.nextElement();
			Symbol sym = table.getSymbol(name);
			
			System.out.format("%1$-77s", sym.getName());
			System.out.format("%1$-35s", sym.getType());
			System.out.println(sym.getLineNo() + 1);
		}
		
		System.out.println("============================================================================" +
		"=============================================");
	}
}
